package org.catspaw.cherubim.security.ss3.rbac;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.dao.DataAccessException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.UserDetailsManager;

import org.catspaw.cherubim.security.PasswordNotMatchedException;
import org.catspaw.cherubim.security.SubjectManager;
import org.catspaw.cherubim.security.rbac.Role;
import org.catspaw.cherubim.security.rbac.User;
import org.catspaw.cherubim.security.rbac.dao.RoleDao;
import org.catspaw.cherubim.security.rbac.dao.UserDao;
import org.catspaw.cherubim.security.rbac.model.UserModel;
import org.catspaw.cherubim.security.ss3.SpringSecuritySubject;

public class RoleBasedUserDetailsManager implements UserDetailsManager {

	private SubjectManager	subjectManager;
	private UserDao			userDao;
	private RoleDao			roleDao;

	public RoleBasedUserDetailsManager(SubjectManager subjectManager,
			UserDao userDao, RoleDao roleDao) {
		this.subjectManager = subjectManager;
		this.userDao = userDao;
		this.roleDao = roleDao;
	}

	public boolean userExists(String username) {
		return userDao.findByUsername(username) != null;
	}

	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException, DataAccessException {
		User user = userDao.findByUsername(username);
		List<? extends Role> roles = roleDao.findByUsername(username);
		Set<String> authorities = new HashSet<String>();
		for (Role role : roles) {
			authorities.add(role.getCode());
		}
		return new SpringSecuritySubject(user, authorities);
	}

	public void changePassword(String oldPassword, String newPassword) {
		SpringSecuritySubject subject = (SpringSecuritySubject) subjectManager
				.getCurrentSubject();
		UserModel user = (UserModel) subject.getUser();
		if (!user.getPassword().equals(oldPassword)) {
			throw new PasswordNotMatchedException(user.getUsername());
		}
		user.setPassword(newPassword);
		userDao.update(user);
	}

	public void createUser(UserDetails userDetails) {
		SpringSecuritySubject subject = (SpringSecuritySubject) userDetails;
		User user = subject.getUser();
		userDao.save((UserModel) user);
	}

	public void deleteUser(String username) {
		User user = userDao.findByUsername(username);
		userDao.delete((UserModel) user);
	}

	public void updateUser(UserDetails userDetails) {
		SpringSecuritySubject subject = (SpringSecuritySubject) userDetails;
		User user = subject.getUser();
		userDao.update((UserModel) user);
	}
}
